/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.common.util.packagemanager;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;
import org.apache.tools.tar.TarOutputStream;

/**
 * This class provides the operations of compressing and decompressing 
 * a Tar.GZ file.
 * @author Jemerson Damasio - jemersonfd@gmail.com
 */
public class TarPackageManager {

	/**
	 * This is a standard buffer size for writing bytes on the disk.
	 */
	private static final int BUFFER_SIZE = 4096; // 4 Kb


	public void packIt(String zipFileName, String fileToCompress) 
	throws IOException {
		File toCompress = new File(fileToCompress);
		TarOutputStream out = new TarOutputStream(
				new GZIPOutputStream(new FileOutputStream(zipFileName)));
		String extractPath = toCompress.getAbsoluteFile().getParent();
		addToTARGZ(toCompress, out, extractPath);
		out.close();

	}

	private void addToTARGZ(File fileToZip, TarOutputStream out, String extractPath) 
	throws IOException {
		if (fileToZip.isDirectory()) {
			File[] files = fileToZip.listFiles();
			for (File toAdd : files) {
				addToTARGZ(toAdd.getAbsoluteFile(), out, extractPath);
			}
		} else {
			BufferedInputStream in = new BufferedInputStream(
					new FileInputStream(fileToZip));
			String newPath = fileToZip.getAbsolutePath().substring(extractPath.length()+1);
			out.putNextEntry(new TarEntry(newPath));
			int len;
			byte[] buf = new byte[BUFFER_SIZE];
			while ((len = in.read(buf)) > 0) {
				out.write(buf, 0, len);
			}
			out.closeEntry();
			in.close();
		}
	}
	
	/**
	 * This method provides an operation of decompressing a standard 
	 * TAR.GZ file to the specified directory.
	 * If the specified directory does no exists it will be created
	 * if possible.
	 * @param file the file under TAR.GZ format to be decompressed.
	 * @param destDir the destination directory.
	 * @throws IOException if any I/O error occur during the extraction.
	 */
	public void unpackIt(String destDir, File file) throws IOException {
		File destinationDirectory = new File(destDir);
		//assuming the file you pass in is not a dir
		destinationDirectory.mkdir();
		//create tar input stream from a .tar.gz file
		TarInputStream tin = 
			new TarInputStream(
					new GZIPInputStream(
							new FileInputStream(file)));

		//get the first entry in the archive                          
		TarEntry tarEntry = tin.getNextEntry();     
		while (tarEntry != null){  
			//create a file with the same name as the tarEntry 
			File destPath = new File(destinationDirectory.toString() + 
					File.separatorChar + tarEntry.getName());
			if (tarEntry.isDirectory()){
				destPath.mkdir();                           
			}
			else {
				FileOutputStream fout = new FileOutputStream(destPath); 
				tin.copyEntryContents(fout);   
				fout.close();                      
			}
			tarEntry = tin.getNextEntry(); 
		}    
		tin.close();
	}

	/**
	 * This methods checks whether the parameter file is under
	 * a tar.gz format.
	 * @param fileToVerify the file to be verified.
	 * @return <code>true</code> if this file is under a tar.gz format,
	 * <code>false</code> otherwise.
	 */
	public static boolean isTarGzFile(File fileToVerify) {
		try {
			TarInputStream tin = 
				new TarInputStream(
						new GZIPInputStream(
								new FileInputStream(fileToVerify)));
		} catch (Exception e) {
			return false;
		}
		return true;
	}

}
